#region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#endregion

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Web;

namespace OshHost.Web
{
	public class HttpRequestResponse : HttpWorkerRequest
	{
		private string _method;
		private string _rawUrl;
		private string _virtualPath;
		private string _queryString;

		private HttpHeaders _requestHeaders;
		private byte[] _requestBody;

		private int _responseStatusCode;
		private string _responseStatusDescription;
		private HttpHeaders _responseHeaders;
		private byte[] _responseBody;

		public HttpRequestResponse(string method, string url, string initRequestHeaders, byte[] requestBody)
		{
			_method = method;
			_rawUrl = url;
			ParseUrl(url, out _virtualPath, out _queryString);
			_requestHeaders = HttpHeaders.Parse(initRequestHeaders);
			_requestBody = requestBody;
			_responseHeaders = new HttpHeaders();
		}

		private void ParseUrl(string uri, out string virtualPath, out string queryString)
		{
			Uri result;
			if(Uri.TryCreate(uri, UriKind.Absolute, out result))
			{
				virtualPath = result.LocalPath;
				if(result.Query.Length > 0)
					queryString = result.Query.Substring(1); // skip '?' character
				else
					queryString = string.Empty;
			}
			else
			{
				virtualPath = string.Empty;
				queryString = string.Empty;
			}
		}

		public string ResponseStatus
		{
			get
			{
				return string.Format("{0} {1} {2}",
					GetHttpVersion(), ResponseStatusCode, ResponseStatusDescription);
			}
		}

		public int ResponseStatusCode
		{
			get { return _responseStatusCode; }
		}

		public string ResponseStatusDescription
		{
			get { return _responseStatusDescription; }
		}

		public HttpHeaders RequestHeaders
		{
			get { return _requestHeaders; }
		}

		public HttpHeaders ResponseHeaders
		{
			get { return _responseHeaders; }
		}

		public byte[] ResponseBody
		{
			get { return _responseBody; }
		}

		#region HttpWorkerRequest Methods
		public override void EndOfRequest()
		{
		}

		public override void FlushResponse(bool finalFlush)
		{
		}

		public override string GetHttpVerbName()
		{
			return _method;
		}

		public override string GetHttpVersion()
		{
			return "HTTP/1.1";
		}

		public override string GetLocalAddress()
		{
			return "127.0.0.1";
		}

		public override int GetLocalPort()
		{
			return 80;
		}

		public override string GetQueryString()
		{
			return _queryString;
		}

		public override string GetRawUrl()
		{
			return _rawUrl;
		}

		public override string GetRemoteAddress()
		{
			return "127.0.0.1";
		}

		public override int GetRemotePort()
		{
			return 0;
		}

		public override string GetUriPath()
		{
			return _virtualPath;
		}

		public override bool HeadersSent()
		{
			return false;
		}

		public override byte[] GetPreloadedEntityBody()
		{
			return _requestBody;
		}

		public override bool IsEntireEntityBodyIsPreloaded()
		{
			return true;
		}

		public override int ReadEntityBody(byte[] buffer, int size)
		{
			int bytesRead = Math.Min(size, _requestBody.Length);
			if(bytesRead > 0)
				Buffer.BlockCopy(_requestBody, 0, buffer, 0, bytesRead);

			return bytesRead;
		}

		public override string GetKnownRequestHeader(int index)
		{
			if(index == HttpWorkerRequest.HeaderContentLength)
			{
				if(_requestBody == null)
					return "0";
				else
					return _requestBody.Length.ToString();
			}
			else
			{
				string requestHeaderName = GetKnownRequestHeaderName(index);
				return _requestHeaders[requestHeaderName];
			}
		}

		public override void SendKnownResponseHeader(int index, string value)
		{
			string name = GetKnownResponseHeaderName(index);
			//Trace.WriteLine(string.Format("RequestResponse.SendKnownResponseHeader({0}, {1})", name, value));

			_responseHeaders.Add(name, value);
		}

		public override void SendUnknownResponseHeader(string name, string value)
		{
			//Trace.WriteLine(string.Format("RequestResponse.SendUnknownResponseHeader({0}, {1})", name, value));
			_responseHeaders.Add(name, value);
		}

		public override void SendCalculatedContentLength(int contentLength)
		{
			_responseHeaders.Add(HttpHeaders.HeaderContentLength, contentLength.ToString());
		}

		public override void SendResponseFromFile(IntPtr handle, long offset, long length)
		{
			Debug.Assert(false);
			throw new NotImplementedException();
		}

		public override void SendResponseFromFile(string filename, long offset, long length)
		{
			using(BinaryReader fileReader = new BinaryReader(
				new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)))
			{
				SendResponseFromFile(fileReader, offset, length);
			}
		}

		public override void SendResponseFromMemory(byte[] data, int length)
		{
			int startIndex = 0;
			if(_responseBody == null)
				_responseBody = new byte[length];
			else
			{
				startIndex = _responseBody.Length;
				int responseBodySize = _responseBody.Length + length;
				byte[] responseBody = new byte[responseBodySize];
				Buffer.BlockCopy(_responseBody, 0, responseBody, 0, _responseBody.Length);
				_responseBody = responseBody;
			}
			Buffer.BlockCopy(data, 0, _responseBody, startIndex, length);
		}

		public override void SendStatus(int statusCode, string statusDescription)
		{
			_responseStatusCode = statusCode;
			_responseStatusDescription = statusDescription;
		}
		#endregion HttpWorkerRequest Methods

		private void SendResponseFromFile(BinaryReader reader, long offset, long length)
		{
			_responseBody = new byte[length];
			reader.BaseStream.Seek(offset, SeekOrigin.Begin);
			reader.Read(_responseBody, 0, (int)length);
		}
	}
}
